﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Numerics;

namespace AEBaseCalcCSharp
{
    class Base
    {
        private int metal;
        private int gas;
        private int crystals;
        private int fertility;
        private int baseFertility;
        private int area;
        private int currentArea;
        private List<Structure> structures = new List<Structure>();
        private List<Defence> defences = new List<Defence>();
        private int position;
        private Astro selectedAstro;
        private string astroType;
        private int energyProduction = 3;
        private int energyConsumption;
        private int population;

        public Base(Astro astro, int position)
        {
            this.selectedAstro = astro;
            this.metal = selectedAstro.metal;

            if (position == 5)
            {
                this.gas = selectedAstro.gas + 2;
            }
            else if (position == 4)
            {
                this.gas = selectedAstro.gas + 1;
            }
            else
            {
                this.gas = selectedAstro.gas;
            }

            this.crystals = selectedAstro.crystals;
            this.baseFertility = selectedAstro.fertility;

            if (position == 3 || position == 2)
            {
                this.baseFertility = baseFertility + 1;
            }

            this.fertility = baseFertility;
            this.area = selectedAstro.area;
            this.currentArea = selectedAstro.area - 1;
            this.position = position;
            this.astroType = selectedAstro.type;

            structures.Add(new UrbanStructure(fertility));
            structures.Add(new SolarPlants(position));
            structures.Add(new GasPlants(position, gas));
            structures.Add(new FusionPlants());
            structures.Add(new AntimatterPlants());
            structures.Add(new ResearchLabs());
            structures.Add(new MetalRefineries(metal));
            structures.Add(new CrystalMines(crystals));
            structures.Add(new RoboticFactories());
            structures.Add(new Shipyards());
            structures.Add(new OrbitalShipyards());
            structures.Add(new Spaceports());
            structures.Add(new CommandCentres());
            structures.Add(new NaniteFactories());
            structures.Add(new AndroidFactories());
            structures.Add(new EconomicCentres());
            structures.Add(new Terraform());
            structures.Add(new MultiLevelPlatforms());
            structures.Add(new OrbitalBase());
            structures.Add(new JumpGate());
            if (astroType == "Planet")
            {
                structures.Add(new BMPlanet());
                defences.Add(new PRPlanet());
                defences.Add(new PSPlanet());
            }
            else if (astroType == "Moon")
            {
                structures.Add(new BMMoon());
                defences.Add(new PRMoon());
                defences.Add(new PSMoon());
            }
            else
            {
                structures.Add(new BMAsteroid());
                defences.Add(new PRAsteroid());
                defences.Add(new PSAsteroid());
            }
            structures.Add(new Capital());

            defences.Add(new Barracks());
            defences.Add(new LaserTurrets());
            defences.Add(new MissileTurrets());
            defences.Add(new PlasmaTurrets());
            defences.Add(new IonTurrets());
            defences.Add(new PhotonTurrets());
            defences.Add(new DisruptorTurrets());
            defences.Add(new DeflectionShields());
        }

        public void incrementLevel(string testStructure, int level)
        {
            for (int i = 0; i < structures.Count(); i++)
            {
                if (string.Compare(structures[i].getStructureName(), testStructure.Replace(" ", ""), true) == 0)
                {
                    if (testStructure == "BiosphereModification")
                    {
                        structures[i].incrementLevel(level);
                        fertility = baseFertility + structures[i].getCurrentFertility();
                        break;
                    }
                    else if (testStructure == "UrbanStructure")
                    {
                        structures[i].incrementLevel(level, fertility);
                    }
                    else
                    {
                        structures[i].incrementLevel(level);
                        break;
                    }
                }
            }

            updateBaseStats();
        }

        public void incrementDefenceLevel(string testDefence, int level)
        {
            for (int i = 0; i < defences.Count(); i++)
            {
                if (string.Compare(defences[i].getDefenceName(), testDefence.Replace(" ", ""), true) == 0)
                {
                    defences[i].incrementLevel(level);
                    break;
                }
            }
            updateBaseStats();
        }

        private void updateBaseStats()
        {
            int tempEnergyProduction = 0;
            int tempEnergyConsumption = 0;
            int tempArea = 0;
            int tempPopulation = 0;
            for (int i = 0; i < structures.Count(); i++)
            {
                if (structures[i].getCurrentEnergy() > 0)
                {
                    tempEnergyProduction += structures[i].getCurrentEnergy();
                }
                else if (structures[i].getCurrentEnergy() < 0)
                {
                    tempEnergyConsumption += structures[i].getCurrentEnergy();
                }
                tempArea += structures[i].getCurrentArea();
                tempPopulation += structures[i].getCurrentPopulation();
            }

            for (int i = 0; i < defences.Count(); i++)
            {
                tempEnergyConsumption += defences[i].getCurrentEnergy();
                tempArea += defences[i].getCurrentArea();
                tempPopulation += defences[i].getCurrentPopulation();
            }

            energyProduction = 3 + tempEnergyProduction;
            energyConsumption = tempEnergyConsumption;
            currentArea = area + tempArea;
            population = tempPopulation;
        }

        public void resetLevels()
        {
            setAllLevels();
        }

        private void setAllLevels()
        {
            for (int i = 0; i < structures.Count(); i++)
            {
                if (structures[i].getStructureName() == "BiosphereModification")
                {
                    fertility = baseFertility - structures[i].getCurrentFertility();
                    structures[i].incrementLevel(0);
                }
                else if (structures[i].getStructureName() == "UrbanStructure")
                {
                    structures[i].incrementLevel(1);
                }
                else
                {
                    structures[i].incrementLevel(0);
                }
            }

            foreach (Defence d in defences)
            {
                d.incrementLevel(0);
            }

            currentArea = area - 1;
        }

        //Getters:-
        public int getMetal()
        {
            return metal;
        }

        public int getGas()
        {
            return gas;
        }

        public int getCrystals()
        {
            return crystals;
        }

        public int getFertility()
        {
            return fertility;
        }

        public int getBaseFertility()
        {
            return baseFertility;
        }

        public int getArea()
        {
            return area;
        }

        public int getPosition()
        {
            return position;
        }

        public int getEnergy(decimal energyTech)
        {
            int totalEnergy = 0;
            if (energyTech > 0)
            {
                totalEnergy = Convert.ToInt32(Math.Ceiling((energyTech * (energyProduction * (decimal)0.05))
                    + energyProduction)) + energyConsumption;
            }
            else
            {
                totalEnergy = energyProduction + energyConsumption;
            }
            return totalEnergy;
        }

        public int getPopulation()
        {
            return population;
        }

        public int getCurrentArea()
        {
            return currentArea;
        }

        public BigInteger getTotalCost(decimal commander)
        {
            BigInteger total = 0;
            foreach (Structure s in structures)
            {
                if (commander > 0)
                {
                    total += Convert.ToInt32(Math.Round(s.getCurrentCost() -
                        (s.getCurrentCost() * (commander / 100)), MidpointRounding.AwayFromZero));
                }
                else
                {
                    total += s.getCurrentCost();
                }
            }

            foreach (Defence d in defences)
            {
                if (commander > 0)
                {
                    total += Convert.ToInt32(Math.Round(d.getCurrentCost() -
                        (d.getCurrentCost() * (commander / 100)), MidpointRounding.AwayFromZero));
                }
                else
                {
                    total += d.getCurrentCost();
                }
            }
            total -= 1;
            return total;
        }

        public int getConstruction(decimal cybernetics)
        {
            int construction = 12;
            foreach (Structure s in structures)
            {
                construction += s.getCurrentConstruction();
            }

            if (cybernetics > 0)
            {
                construction += Convert.ToInt32(Math.Ceiling(cybernetics * (construction
                    * (decimal)0.05)));
            }

            return construction;
        }

        public TimeSpan getTotalTime(decimal cybernetics, decimal commander)
        {
            int construction = getConstruction(cybernetics);
            BigInteger totalCost = getTotalCost(commander);
            long seconds = Convert.ToInt64(Math.Round(((((decimal)totalCost / construction) * 60) * 60),
                MidpointRounding.AwayFromZero));
            TimeSpan time = TimeSpan.FromSeconds(seconds);
            return time;
        }

        public string getProduction(decimal cybernetics)
        {
            int production = 0;
            foreach (Structure s in structures)
            {
                production += s.getCurrentProduction();
            }

            if (cybernetics > 0)
            {
                production += Convert.ToInt32(Math.Ceiling(cybernetics * (production
                    * (decimal)0.05)));
            }

            return production.ToString();
        }
    }
}
